// npm install @reduxjs/toolkit
// toolkit是对redux的封装，我们不用手写action和reducer这些繁琐重复的代码，toolkit会帮我们处理这些，我们只需要专注于写修改state的逻辑即可
// 以下是toolkit代码实现的简化版本
import { combineReducers, createStore } from "./redux";

// const builder = {
//     asyncFns: {},
//     addCase(promiseState, changeStateFn) {
//         console.log(this)
//         this.asyncFns[promiseState] = changeStateFn
//     }
//   }
let globalStore;
// store分片
function createSlice({ name, initialState, reducers, extraReducers }) {
  let currentState = { ...initialState };
  let actions = {};
  const asyncFns = {};
  for (let [key, changeStateFn] of Object.entries(reducers)) {
    // dispatch(someAction(value))
    // const action = {
    //   payload: value,
    //   type: name + "/" + key,
    // }
    actions[key] = (payload) => {
      changeStateFn(currentState, payload)
      return {
        data: currentState[key],
        type: name + "/" + key,
      }
    }
  }
  extraReducers({
    addCase(promiseState, changeStateFn) {
      asyncFns[promiseState] = changeStateFn;
    },
  });

  function reducer(state = currentState, action) {
    // switch (action.type) {
    //   // 省略其他 cases
    //   case "todos/todosLoading": {
    //     // ❌ 警告：仅示例 - 不要在普通 reducer 中执行此操作！
    //     state.status = "loading";
    //     return state;
    //   }
    //   default:
    //     return state;
    // }
    for (let [key, reducerFn] of Object.entries(reducers)) {
      if (action.type === name + "/" + key) {
        reducerFn(state, action);
        currentState = { ...state };
        return currentState;
      }
    }
    for (let [key, reducerFn] of Object.entries(asyncFns)) {
      if (action.type === key) {
        reducerFn(state, action);
        currentState = { ...state };
        return currentState;
      }
    }
    return state;
  }

  return {
    actions,
    reducer,
  };
}

// 创建store
function configureStore({ reducer }) {
  const combineReducer =
    typeof reducer === "function" ? reducer : combineReducers(reducer);
  const store = createStore(combineReducer);
  globalStore = store;
  return store;
}

// 创建异步方法
function createAsyncThunk(name, asyncFn) {
  const promiseState = {
    pending: `${name}/pending`,
    fulfilled: `${name}/fulfilled`,
    rejected: `${name}/rejected`,
  };
  function thunk(...args) {
    return async (dispatch) => {
      dispatch({
        type: promiseState.pending,
      });
      try {
        const data = await asyncFn(...args);
        dispatch({
          type: promiseState.fulfilled,
          payload: data,
        });
      } catch (err) {
        dispatch({
          type: promiseState.rejected,
          payload: err,
        });
      }
    };
  }
  thunk.pending = promiseState.pending;
  thunk.fulfilled = promiseState.fulfilled;
  thunk.rejected = promiseState.rejected;
  return thunk;
}

// 该 API 为具有归一化 state 的典型数据更新操作预先构建了 reducer。包括从 slice 中添加、更新和删除 items。createEntityAdapter 还会生成一些用于从 store 中读取值的记忆化 selectors。
// 通俗讲就是处理list数组的增删改查逻辑，封装起来直接使用即可
function createEntityAdapter(options) {
  const currentState = {
    // 每个对象唯一的id，必须是string或number
    ids: [],
    // 范式化的对象，实体id映射到相应实体对象的查找表，即key为id,value为id所在对象的值，
    entities: {},
  };
  function getInitialState(otherParams) {
    return { ...currentState, ...otherParams };
  }

  function addMany(state, action) {
    action.payload.forEach((item) => {
      const id =
        typeof options.selectId === "function"
          ? options.selectId(item)
          : item[options.selectId];
      currentState.ids.push(id);
      currentState.entities[id] = item;
    });
  }
  // action可以是action也可以是数据
  function updateOne(state, action) {
    // data约定为固定格式{id: string | number, changes: T}
    const data = action.payload || action;
    const idx = state.entities.findIndex((item) => {
      const id =
        typeof options.selectId === "function"
          ? options.selectId(item)
          : item[options.selectId];
      return id === data.id;
    });
    state.entities.splice(idx, 1, data);
    state.ids.splice(idx, 1, data.id);
  }
  function selectById(state, id) {
    return state.entities[id];
  }
  function selectIds(state) {
    return state.ids;
  }
  function selectAll(state) {
    return state.entities;
  }
  function getSelectors(fn) {
    // return fn(globalStore.getState())
    const state = fn(globalStore.getState());
    return {
      selectAll: () => selectAll(state),
      selectById: (id) => selectById(state, id),
    };
  }
  return {
    getInitialState,
    getSelectors,
    addOne,
    addMany,
    upsertOne,
    upsertMany,
    updateOne,
    updateMany,
    removeOne,
    setAll,
  };
}

// 过滤列表数据的方法,会记忆化处理结果数据，有点类似computed
function createSelector(...selectAllFn) {
  const filterResultFn = selectAllFn.splice(-1);
  // const result = selectAllFn()
  const result = selectAllFn.reduce((result, fn) => {
    return fn(result);
  });
  return filterResultFn(result);
}

export {
  createSlice,
  configureStore,
  createAsyncThunk,
  createEntityAdapter,
  createSelector,
};
